#ifndef QK_THREAD_HPP
#define QK_THREAD_HPP
#include <windows.h>
#include <process.h>

typedef unsigned(__stdcall* _beginthreadex_proc_type)(void*);

class QKThread{
protected:
	HANDLE m_thread;

public:
	QKThread(_beginthreadex_proc_type fn, LPVOID data){
		m_thread = (HANDLE)_beginthreadex(NULL, 0, fn, data, 0, NULL);
	}

	QKThread(_beginthreadex_proc_type fn) {
		m_thread = (HANDLE)_beginthreadex(NULL, 0, fn, NULL, 0, NULL);
	}

	QKThread(_beginthreadex_proc_type fn, LPVOID data, int priority) {
		m_thread = (HANDLE)_beginthreadex(NULL, 0, fn, data, CREATE_SUSPENDED, NULL);
		SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
		ResumeThread(m_thread);
	}

	~QKThread() {
		if (m_thread != NULL) {
			wait();
			CloseHandle(m_thread);
		}
	}

	DWORD  resume() {
		return ResumeThread(m_thread);
	}

	DWORD  suspend() {
		return SuspendThread(m_thread);
	}

	bool  wait(DWORD timeout) {
		return WaitForSingleObject(m_thread, timeout) == WAIT_OBJECT_0;
	}

	bool  wait() {
		return WaitForSingleObject(m_thread, INFINITE) == WAIT_OBJECT_0;
	}
};

class QKMutex {
protected:
	HANDLE m_mutex;
public:

	QKMutex() :m_mutex(NULL) {
	}

	~QKMutex() {
		if (m_mutex != NULL) {
			CloseHandle(m_mutex);
		}
	}

	BOOL Create() {
		m_mutex = CreateMutex(NULL, FALSE, NULL);
		return m_mutex != NULL;
	}

	BOOL Create(TCHAR * name) {
		m_mutex = CreateMutex(NULL, FALSE, name);
		return m_mutex != NULL;
	}

	BOOL Open(TCHAR* name) {
		m_mutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, name);
		return m_mutex != NULL;
	}

	bool attempt() {
		return (WaitForSingleObject(m_mutex, 0) == WAIT_OBJECT_0) ? true : false;
	}
	

	bool lock() {
		return WaitForSingleObject(m_mutex, INFINITE) == WAIT_OBJECT_0;
	}

	void unlock(){
		ReleaseMutex(m_mutex);
	}
};

class QKCriticalSection {
protected:
	CRITICAL_SECTION cs;
public:

	QKCriticalSection() {
		InitializeCriticalSection(&cs);
	}

	QKCriticalSection(DWORD dwSpinCount) {
		InitializeCriticalSectionAndSpinCount(&cs, dwSpinCount);
	}

	~QKCriticalSection() {
		DeleteCriticalSection(&cs);
	}

	void enter() {
		EnterCriticalSection(&cs);
	}

	void leave() {
		LeaveCriticalSection(&cs);
	}

	bool attempt() {
		return TryEnterCriticalSection(&cs) != 0;
	}
};

class QKSemaphore {
protected:
	HANDLE m_sem;

public:
	QKSemaphore(): m_sem(NULL){
	}

	~QKSemaphore() {
		if (m_sem != NULL) {
			CloseHandle(m_sem);
		}
	}

	bool Create(int cMax) {
		m_sem = CreateSemaphore(NULL, 0, cMax, NULL);
		return (m_sem != NULL);
	}

	bool Create(TCHAR *name, int cMax) {
		m_sem = CreateSemaphore(NULL, 0, cMax, name);
		return (m_sem != NULL);
	}

	bool Open(TCHAR *name) {
		m_sem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name);
		return (m_sem != NULL);
	}

	void post() {
		ReleaseSemaphore(m_sem, 1, NULL);
	}

	bool wait() {
		return WaitForSingleObject(m_sem, INFINITE) == WAIT_OBJECT_0;
	}

	bool wait(DWORD timeout) {
		return WaitForSingleObject(m_sem, timeout) == WAIT_OBJECT_0;
	}
};

class QKSignal {
protected:
	HANDLE m_event;

public:
	QKSignal() {
	}

	~QKSignal() {
		if (m_event != NULL) {
			CloseHandle(m_event);
		}
	}

	bool Create(bool isBroadcast) {
		m_event = CreateEvent(NULL, true, isBroadcast, NULL);
		return (m_event != NULL);
	}

	bool Create(bool isBroadcast, TCHAR* name) {
		m_event = CreateEvent(NULL, true, isBroadcast, name);
		return (m_event != NULL);
	}

	bool wait() {
		return WaitForSingleObject(m_event, INFINITE) == WAIT_OBJECT_0;
	}

	bool wait(DWORD timeout) {
		return WaitForSingleObject(m_event, timeout) == WAIT_OBJECT_0;
	}
	
	void signal() {
		PulseEvent(m_event);
	}

	void broadcast() {
		PulseEvent(m_event);
	}
};

#endif

